﻿using System.Text;
using Admin.ApplicationLib.Entities;
using Admin.ApplicationLib.Repositories;
using Admin.ApplicationLib.Specifications;
using Admin.CommonLib.Models.User;
using AutoMapper;
using Microsoft.AspNetCore.Identity;
using Swimj.CommonLib.Base;
using Swimj.Core.Providers;
using Swimj.Core.Securities;

namespace Admin.ApplicationLib.Services
{
    public class UserService : IUserService
    {
        private readonly UserManager<UserEntity> _userManager;
        private readonly IUserRepository _userRepository;
        private readonly ISecurityUser _securityUser;
        private readonly IDateTimeProvider _dateTimeProvider;
        private readonly IExcelProvider _excelProvider;
        private readonly IMapper _mapper;

        public UserService(UserManager<UserEntity> userManager,
            IUserRepository userRepository,
            ISecurityUser securityUser,
            IDateTimeProvider dateTimeProvider,
            IExcelProvider excelProvider,
            IMapper mapper)
        {
            _userManager = userManager;
            _userRepository = userRepository;
            _securityUser = securityUser;
            _dateTimeProvider = dateTimeProvider;
            _excelProvider = excelProvider;
            _mapper = mapper;
        }

        public async Task<PaginatedResult<UserInfoResponseDto>> QueryUsersByPageAsync(UserSearchRequestDto model)
        {
            var normalizeName = _userManager.NormalizeName(_securityUser.Name);

            var userSpecification = new UserSpecification(model, normalizeName);

            var userEntities = await _userRepository.ListAsync(userSpecification);

            var count = await _userRepository.CountAsync(userSpecification);

            return await PaginatedResult<UserInfoResponseDto>.SuccessAsync(
                _mapper.Map<List<UserInfoResponseDto>>(userEntities),
                count,
                model.Page, model.Limit);
        }

        public async Task<Result<IList<UserInfoResponseDto>>> QueryUsersAsync(UserSearchRequestDto model)
        {
            var normalizeName = _userManager.NormalizeName(_securityUser.Name);

            var userSpecification = new UserSpecification(model, normalizeName);

            var userEntities = await _userRepository.ListAsync(userSpecification);

            return await Result<IList<UserInfoResponseDto>>.SuccessAsync(
                _mapper.Map<List<UserInfoResponseDto>>(userEntities));
        }

        public async Task<Result<UserInfoResponseDto>> GetUserAsync(Guid id)
        {
            var userEntity = await _userRepository.GetByIdAsync(id);
            if (userEntity == null)
            {
                return await Result<UserInfoResponseDto>.FailAsync("");
            }

            return await Result<UserInfoResponseDto>.SuccessAsync(_mapper.Map<UserInfoResponseDto>(userEntity));
        }

        public async Task<Result<UserInfoResponseDto>> CreateUserAsync(UserEditRequestDto model)
        {
            var normalizeName = _userManager.NormalizeName(model.UserName);
            if (normalizeName.Equals("ADMIN"))
            {
                return await Result<UserInfoResponseDto>.FailAsync("用户名不能为admin");
            }

            var userEntity = _mapper.Map<UserEntity>(model);
            var identityResult = await _userManager.CreateAsync(userEntity, model.Password);

            if (identityResult.Succeeded)
            {
                return await Result<UserInfoResponseDto>.SuccessAsync(_mapper.Map<UserInfoResponseDto>(userEntity));
            }
            else
            {
                return await Result<UserInfoResponseDto>.FailAsync(
                    identityResult.Errors.Select(i => i.Description).ToList());
            }
        }

        public async Task<Result<UserInfoResponseDto>> UpdateUserAsync(Guid id, UserEditRequestDto model)
        {
            var userEntity = await _userRepository.GetByIdAsync(id);
            if (userEntity == null)
            {
                throw new Exception();
            }

            _mapper.Map(model, userEntity);

            await _userRepository.UpdateAsync(userEntity);

            return await Result<UserInfoResponseDto>.SuccessAsync(_mapper.Map<UserInfoResponseDto>(userEntity));
        }

        public async Task<Result<UserInfoResponseDto>> DeleteUserAsync(Guid id)
        {
            var userEntity = await _userRepository.GetByIdAsync(id);
            if (userEntity == null)
            {
                return await Result<UserInfoResponseDto>.FailAsync("");
            }

            await _userRepository.DeleteAsync(userEntity);

            return await Result<UserInfoResponseDto>.SuccessAsync(_mapper.Map<UserInfoResponseDto>(userEntity));
        }

        public async Task<Tuple<Stream, string>> ExportAsync(UserSearchRequestDto model)
        {
            var normalizeName = _userManager.NormalizeName(_securityUser.Name);

            var fileName = $"UserListExport_{_dateTimeProvider.GetCurrentDateTime():yyyyMMddHHmmss}.xlsx";
            var userSpecification = new UserSpecification(model, normalizeName);
            var userEntities = await _userRepository.ListAsync(userSpecification);

            var list = _mapper.Map<List<UserInfoResponseDto>>(userEntities);

            var stream = _excelProvider.WriteToStream(list, "Sheet1");

            return new Tuple<Stream, string>(stream, fileName);
        }

        public Task<Tuple<Stream, string>> ExportTemplateAsync()
        {
            var fileName = $"UserTemplateExport_{_dateTimeProvider.GetCurrentDateTime():yyyyMMddHHmmss}.xlsx";

            var stream = _excelProvider.WriteToStream<UserTemplateResponseDto>("Sheet1");

            return Task.FromResult(new Tuple<Stream, string>(stream, fileName));
        }

        public async Task<object?> ImportAsync(int importType, MemoryStream memoryStream)
        {
            try
            {
                var userTemplateResponseDtos =
                    _excelProvider.ReadToCollection<UserTemplateResponseDto>(memoryStream);

                if (userTemplateResponseDtos.Count == 0)
                {
                    return await Result.FailAsync("导入的数据不能为空");
                }

                IList<UserImportResponseDto> importDatas = new List<UserImportResponseDto>();

                // 校验数据
                foreach (var item in userTemplateResponseDtos)
                {
                    var userImportResponseDto = new UserImportResponseDto(item);
                    StringBuilder sb = new StringBuilder();
                    if (string.IsNullOrEmpty(item.UserName))
                    {
                        sb.Append("用户名不能为空；");
                    }

                    if (string.IsNullOrEmpty(item.RealName))
                    {
                        sb.Append("用户名称不能为空；");
                    }

                    userImportResponseDto.ErrorMessage = sb.ToString();

                    importDatas.Add(userImportResponseDto);
                }

                var hasError = importDatas.Any(i => !string.IsNullOrEmpty(i.ErrorMessage));
                if (!hasError)
                {
                    var userEntities = _mapper.Map<IList<UserEntity>>(userTemplateResponseDtos);

                    await _userRepository.AddRangeAsync(userEntities);
                }

                return await Result<IList<UserImportResponseDto>>.SuccessAsync(importDatas);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
    }
}